package wiki.tools.vidition.droid.util;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.text.TextUtils;
import android.util.Log;

public final class HttpClient {
	public static final String USER_AGENT_VALUE = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; EmbeddedWB 14.52 from: http://www.bsalsa.com/ EmbeddedWB 14.52; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.1; .NET CLR 1.0.3705; .NET CLR 3.0.04506.30)";

	/**
	 * 命令分隔�?'$$'.
	 */
	public static final String HTTP_CLIENT_CMD_SPLITOR = "@@";

	/**
	 * POST 参数分隔�?'&'.
	 */
	public static final String POST_PARAMETER_SPLITOR = "&";

	/**
	 * POST 参数�?值分隔符 '='�?
	 */
	private static final String POST_PARAMETER_KV_SPLITOR = "=";

	/**
	 * 默认�?Cookie 内容�?
	 */
	private static String cookie;

	/**
	 * 从HTML头中找到编码字段
	 */
	private static Pattern CONTENT_TYPE_CHARSET_PATTERN = Pattern
			.compile("charset=([-_a-zA-Z0-9]*)");

	/**
	 * Cookie 表�?
	 */
	@SuppressWarnings("unused")
	private static Map<String, String> cookieMap = new HashMap<String, String>();

	/**
	 * 初始�?HttpClient 的一个新实例�?
	 */
	public HttpClient() {

	}

	/**
	 * �?GET 方法请求给定�?URL，并且返�?HTTP 响应的内容�?
	 * 
	 * @param url
	 *            要请求的 URL�?
	 * @param keepCookie
	 *            是否保存 Cookie 信息�?
	 * @return 给定 URL 返回的响应�?
	 */
	public String getMethod(String url, boolean keepCookie) {
		return getMethod(url, null, keepCookie);
	}

	/**
	 * �?GET 方法请求给定�?URL，并且返�?HTTP 响应的内容�?
	 * 
	 * @param url
	 *            要请求的 URL�?
	 * @param heads
	 *            请求包含�?HTTP 头�?
	 * @param keepCookie
	 *            是否保存 Cookie 信息�?
	 * @return 给定 URL 返回的响应�?
	 */
	public String getMethod(String url, Map<String, String> heads,
			boolean keepCookie) {
		if (url == null || url.length() == 0) {
			return "Requst url could not be null or empty.";
		}

		StringBuffer result = new StringBuffer();
		try {
			HttpURLConnection httpURLConnection = getHttpURLConnection(url,
					keepCookie);
			if (heads != null) {
				int index = 0;
				for (Iterator<Entry<String, String>> iter = heads.entrySet()
						.iterator(); iter.hasNext(); index++) {
					Entry<String, String> entry = iter.next();
					httpURLConnection.setRequestProperty(entry.getKey(), entry
							.getValue());
				}
			}
			// Set request properties.
			settingHttpRequestHeader(httpURLConnection);
			httpURLConnection.setRequestMethod("GET");

			// Getting or setting cookie
			gettingOrSettingCookie(httpURLConnection, keepCookie);

			InputStream httpInputStream = httpURLConnection.getInputStream();
			String encoding = httpURLConnection.getContentEncoding();
			if (encoding == null) {
				String contentType = httpURLConnection.getContentType();
				if (TextUtils.isEmpty(contentType)) {
					int i = contentType.indexOf("charset=");
					if (i != -1) {
						encoding = contentType.substring(i + 8);
					}
				}
			}
			BufferedReader httpBufferedReader;
			if (encoding != null) {
				httpBufferedReader = new BufferedReader(new InputStreamReader(
						httpInputStream, "UTF-8"));
			} else {
				httpBufferedReader = new BufferedReader(new InputStreamReader(
						httpInputStream));
			}
			result.append(readBufferedContent(httpBufferedReader));

			// Connect to host.
			httpURLConnection.connect();

		} catch (IOException e) {
			Log.e("HttpClient", e.toString());
			return null;
		}
		return result.toString();
	}

	/**
	 * �?POST 方法请求给定�?URL，并且返�?HTTP 响应的内容�?
	 * 
	 * @param url
	 *            要请求的 URL�?
	 * @param parameters
	 *            要发送的参数�?
	 * @param keepCookie
	 *            是否保存 Cookie 信息�?
	 * @return 给定 URL 返回的响应�?
	 */
	public String postMethod(String url, Map<String, String> parameters,
			boolean keepCookie) {
		return postMethod(url, null, parameters, keepCookie);
	}

	/**
	 * �?POST 方法请求给定�?URL，并且返�?HTTP 响应的内容�?
	 * 
	 * @param url
	 *            要请求的 URL�?
	 * @param parameters
	 *            要发送的参数�?
	 * @param keepCookie
	 *            是否保存 Cookie 信息�?
	 * @return 给定 URL 返回的响应�?
	 */
	public String postMethod(String url, Map<String, String> heads,
			Map<String, String> parameters, boolean keepCookie) {
		// StringBuffer httpResponse = new StringBuffer();
		String postResponse = null;
		HttpURLConnection httpURLConnection = null;
		OutputStream httpOutputStream = null;
		try {
			// Build post parameters string
			StringBuffer postParams = new StringBuffer();
			if (parameters != null) {
				int index = 0;
				for (Iterator<Entry<String, String>> iter = parameters
						.entrySet().iterator(); iter.hasNext(); index++) {
					Entry<String, String> entry = iter.next();
					postParams.append(index != 0 ? POST_PARAMETER_SPLITOR : "");
					postParams.append(entry.getKey());
					postParams.append(POST_PARAMETER_KV_SPLITOR);
					postParams.append(entry.getValue());
				}
			}
			httpURLConnection = getHttpURLConnection(url, keepCookie);
			// Set request properties.
			settingHttpRequestHeader(httpURLConnection);
			if (heads != null) {
				int index = 0;
				for (Iterator<Entry<String, String>> iter = heads.entrySet()
						.iterator(); iter.hasNext(); index++) {
					Entry<String, String> entry = iter.next();
					httpURLConnection.setRequestProperty(entry.getKey(), entry
							.getValue());
				}
			}
			// Set request method with 'POST'
			httpURLConnection.setRequestMethod("POST");
			httpURLConnection.setRequestProperty("Content-Type",
					"application/x-www-form-urlencoded");
			// application/x-www-form-urlencoded;charset=UTF-8
			// Set connection output is true.
			httpURLConnection.setDoOutput(true);

			httpURLConnection.setRequestProperty("Content-Length", String
					.valueOf(postParams.toString().length()));

			// Get Http output stream
			httpOutputStream = httpURLConnection.getOutputStream();
			httpOutputStream.write(postParams.toString().getBytes());
			// Getting or setting cookie
			gettingOrSettingCookie(httpURLConnection, keepCookie);
			String contentType = httpURLConnection.getContentType();
			String encoding = null;
			Matcher matcher = CONTENT_TYPE_CHARSET_PATTERN.matcher(contentType);
			if (matcher.find()) {
				encoding = matcher.group(1);
			}
			InputStream inputStream = httpURLConnection.getInputStream();
			ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
			byte[] buffer = new byte[8192];
			int size = -1;
			while ((size = inputStream.read(buffer)) != -1) {
				byteStream.write(buffer, 0, size);
			}
			byte[] data = byteStream.toByteArray();
			if (encoding != null) {
				postResponse = new String(data, encoding);
			} else {
				postResponse = new String(data, "utf-8");
			}

			/*
			 * BufferedReader httpBufferedReader = new BufferedReader( new
			 * InputStreamReader(httpURLConnection.getInputStream()));
			 * httpResponse.append(readBufferedContent(httpBufferedReader));
			 */
		} catch (Exception e) {
			Log.e("HttpClient", e.toString());
			return null;
		} finally {
			try {
				httpOutputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		return postResponse;
	}

	/**
	 * �?POST 方法请求给定�?URL，并且返�?HTTP 响应的内容�?
	 * 
	 * @param url
	 *            要请求的 URL�?
	 * @param soapEnvelope
	 *            要发送的 SOAP 请求�?
	 * @param keepCookie
	 *            是否保存 Cookie 信息�?
	 * @return 给定 URL 返回的响应�?
	 */
	public String postSoap(String url, String soapAction, String soapEnvelope) {

		Log.i("HttpClient", "Posting SOAP to " + url + " Action : "
				+ soapAction + " Envelope : " + soapEnvelope);
		StringBuffer httpResponse = new StringBuffer();

		HttpURLConnection httpURLConnection = null;
		OutputStream httpOutputStream = null;
		try {
			httpURLConnection = getHttpURLConnection(url, false);
			// Set request method with 'POST'
			httpURLConnection.setRequestMethod("POST");
			httpURLConnection.setRequestProperty("Content-Type",
					"text/xml; charset=utf-8");
			// Set connection output is true.
			httpURLConnection.setDoOutput(true);
			byte[] buffer = soapEnvelope.getBytes("utf8");
			// httpURLConnection.setRequestProperty("Content-Length",
			// String.valueOf(buffer.length));
			httpURLConnection.setRequestProperty("Content-Length", String
					.valueOf(buffer.length));
			httpURLConnection.setRequestProperty("SOAPAction", soapAction);
			// Get Http output stream
			httpOutputStream = httpURLConnection.getOutputStream();
			httpOutputStream.write(buffer);
			// Getting or setting cookie
			gettingOrSettingCookie(httpURLConnection, false);

			BufferedReader httpBufferedReader = new BufferedReader(
					new InputStreamReader(httpURLConnection.getInputStream()));
			httpResponse.append(readBufferedContent(httpBufferedReader));
		} catch (Exception e) {
			Log.e("HttpClient", e.toString());
			return null;
		} finally {
			try {
				if (httpOutputStream != null) {
					httpOutputStream.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
				Log.e("HttpClient", e.toString());
			}
		}
		return httpResponse != null ? httpResponse.toString() : null;
	}

	/**
	 * Setting HTTP request header properties
	 * 
	 * @param httpURLConnection
	 */
	private void settingHttpRequestHeader(HttpURLConnection httpURLConnection) {
		if (httpURLConnection == null)
			return;
		httpURLConnection.setRequestProperty("User-Agent", USER_AGENT_VALUE);
		// TODO setting some other properties here . . .
	}

	/**
	 * Get HttpURLConnection by specified url string.
	 * 
	 * @param url
	 * @return
	 * @throws IOException
	 */
	private HttpURLConnection getHttpURLConnection(String url,
			boolean keepCookie) throws IOException {
		URL urlObj = new URL(url);
		URLConnection urlConnection = urlObj.openConnection();
		if (urlConnection instanceof HttpURLConnection)
			return (HttpURLConnection) urlConnection;
		throw new MalformedURLException();
	}

	/**
	 * Read bufferedReader buffered content.
	 * 
	 * @param bufferedReader
	 * @return
	 */
	private String readBufferedContent(BufferedReader bufferedReader) {
		if (bufferedReader == null)
			return null;
		StringBuffer result = new StringBuffer();
		String line = null;
		try {
			while ((line = bufferedReader.readLine()) != null) {
				result.append(line);
			}
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
		return result.toString();
	}

	/**
	 * 解析查询字符串�?
	 * 
	 * @param parameterString
	 *            要解析的查询字符串�?
	 * @return
	 */
	public static Map<String, String> parsePostParameters(String parameterString) {
		if (parameterString == null || parameterString.length() == 0)
			return null;
		Map<String, String> result = new HashMap<String, String>();

		// only one parameter key-value pair
		if (parameterString.indexOf(POST_PARAMETER_SPLITOR) == -1) {
			if (parameterString.indexOf(POST_PARAMETER_KV_SPLITOR) != -1)
				result.put(parameterString.split(POST_PARAMETER_KV_SPLITOR)[0],
						parameterString.split(POST_PARAMETER_KV_SPLITOR)[1]);
		} else {
			String[] keyValues = parameterString.split(POST_PARAMETER_SPLITOR);
			for (int i = 0; i < keyValues.length; i++) {
				String keyValue = keyValues[i];
				result.put(keyValue.split(POST_PARAMETER_KV_SPLITOR)[0],
						keyValue.split(POST_PARAMETER_KV_SPLITOR)[1]);
			}
		}
		return result;
	}

	/**
	 * Get or set cookie.
	 * 
	 * @param httpURLConnection
	 * @param keepCookie
	 */
	private void gettingOrSettingCookie(HttpURLConnection httpURLConnection,
			boolean keepCookie) {
		if (!keepCookie)
			return;
		// Getting or setting cookie.
		if (cookie == null || cookie.length() == 0) {
			Map<String, List<String>> heads = httpURLConnection
					.getHeaderFields();
			if (heads == null)
				return;
			String setCookie = "";
			List<String> list = heads.get("set-cookie");
			for (String name : list) {
				int index = name.indexOf(";");
				if (index != -1) {
					setCookie += name.substring(0, index + 1);
				} else {
					setCookie += name + ";";
				}
			}
			if (setCookie != "") {
				cookie = setCookie;// setCookie.substring(0,
				// setCookie.indexOf(";"));
			}
		} else if (cookie != null) {
			httpURLConnection.setRequestProperty("Cookie", cookie);
		}
	}

	/**
	 * Downloads and returns an image.
	 * 
	 * @param imageURL
	 *            is the URL where the image is found.
	 * @param useCaches
	 *            is a flag to indicate if the image should be cached or not.
	 * @return The image.
	 */
	public static Bitmap fetchImage(String imageURL, boolean useCaches) {
		Bitmap image = null;

		if (imageURL != null) {
			InputStream is = null;

			try {
				// Open a new URL and get the InputStream to load data from it.
				URL url = new URL(imageURL);
				URLConnection conn = url.openConnection();
				conn.setConnectTimeout(0);
				conn.setReadTimeout(0);
				conn.setUseCaches(useCaches);
				conn.connect();
				is = conn.getInputStream();

				// Create a bitmap.
				image = BitmapFactory.decodeStream(is);

				// Note we do not want to save the image to the file system.
				// AdMob
				// servers may use the download for accounting and optimization
				// purposes.
			} catch (IOException e) {
				Log.w("HttpClient", "Problem getting image:  " + imageURL, e);
			} finally {
				if (is != null) {
					try {
						is.close();
					} catch (IOException e) {
						// Ignore and continue.
					}
				}
			}
		}

		return image;
	}

	/**
	 * Download data from url
	 * 
	 * @param url
	 * @return
	 */
	public static byte[] fetchData(String url) {
		byte[] data = null;

		if (url != null) {
			InputStream is = null;

			try {
				// Open a new URL and get the InputStream to load data from it.
				URL url2 = new URL(url);
				URLConnection conn = url2.openConnection();
				conn.setConnectTimeout(0);
				conn.setReadTimeout(0);
				conn.connect();
				is = conn.getInputStream();
				byte[] tmp = new byte[2048];
				ByteArrayOutputStream stream = new ByteArrayOutputStream();
				int len = -1;
				while ((len = is.read(tmp)) != -1) {
					stream.write(tmp, 0, len);
				}
				data = stream.toByteArray();
				// Note we do not want to save the image to the file system.
				// AdMob
				// servers may use the download for accounting and optimization
				// purposes.
			} catch (Exception e) {
				Log.w("HttpClient", "Problem getting data:  " + url, e);
			} finally {
				if (is != null) {
					try {
						is.close();
					} catch (IOException e) {
						// Ignore and continue.
					}
				}
			}
		}

		return data;
	}
}